package com.example.shop.goods.service.impl;

import com.example.shop.common.api.ServiceReturn;
import com.example.shop.common.api.ServiceStateCode;
import com.example.shop.common.bo.Page;
import com.example.shop.common.util.CachedThreadPoolUtil;
import com.example.shop.es.dto.ElasticSearchQueryParam;
import com.example.shop.es.service.ElasticSearchClient;
import com.example.shop.goods.dao.EvaluationBrowseInfoDao;
import com.example.shop.goods.dao.EvaluationDetailBrowseInfoDao;
import com.example.shop.goods.dto.*;
import com.example.shop.goods.enums.EvaluationSortRules;
import com.example.shop.goods.enums.EvaluationType;
import com.example.shop.goods.enums.SortOrder;
import com.example.shop.goods.service.BrowseEvaluationService;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BrowseEvaluationServiceImpl implements BrowseEvaluationService {

    private final EvaluationBrowseInfoDao browseInfoDao;
    private final EvaluationDetailBrowseInfoDao detailBrowseInfoDao;
    private final ElasticSearchClient esClient;

    public BrowseEvaluationServiceImpl(EvaluationBrowseInfoDao browseInfoDao, EvaluationDetailBrowseInfoDao detailBrowseInfoDao, ElasticSearchClient esClient) {
        this.browseInfoDao = browseInfoDao;
        this.detailBrowseInfoDao = detailBrowseInfoDao;
        this.esClient = esClient;
    }

    /**
     * 由于mybatis代理mapper生成bean于@PostConstruct执行顺序问题，
     * 因此会报错
     */
//    @PostConstruct
//    public void init(){
//        esClient.saveDocument(detailBrowseInfoDao.selectById(1L));
//    }


    private ElasticSearchQueryParam toElasticSearchQueryParam(EvaluationQueryParam queryParam){
        BoolQueryBuilder esQueryParamBuilder = QueryBuilders.boolQuery();
        //查询参数里的条件
        if(queryParam.getGoodsId()!=null){
            esQueryParamBuilder.must(QueryBuilders.termQuery("goodsId",queryParam.getGoodsId()));
        }
        if(queryParam.getUserPurchasedGoodsClass()!=null){
            esQueryParamBuilder.must(
                    QueryBuilders.termQuery("userPurchasedGoods.goodsClass.keyword",queryParam.getUserPurchasedGoodsClass())
            );
        }
        if(queryParam.getEvaluationType()!=null){
            esQueryParamBuilder.must(QueryBuilders.termQuery("evaluationType.keyword",queryParam.getEvaluationType()));
        }
        //查询参数里的排序
        Sort sort;
        Sort.Direction direction = Sort.Direction.valueOf(queryParam.getSortOrder().name());
        if(queryParam.getSortRules()!=null){
            sort = Sort.by(direction,queryParam.getSortRules().getEsField());
        }else{
            sort = Sort.by(direction,EvaluationSortRules.EVALUATION_DATE.getEsField());
        }
        ElasticSearchQueryParam.Builder builder = ElasticSearchQueryParam.builder(esQueryParamBuilder);
        Page page = queryParam.getPage();
        //设置排序
        builder.setSort(sort)
                //设置分页
                .setPageable(PageRequest.of(page.getPageIndex(),page.getPageSize()));
        return builder.build();
    }

    @Override
    public ServiceReturn<EvaluationDetailBrowseInfo> obtainDetailInfo(long evaluationId) {
        EvaluationDetailBrowseInfo info = esClient.getDocumentMustClass(evaluationId, EvaluationDetailBrowseInfo.class);
        if(info == null){
            info = detailBrowseInfoDao.selectById(evaluationId);
            if(info==null){
                //将数据库查到的数据保存到
                CachedThreadPoolUtil.submit(()->esClient.saveDocument(new EvaluationDetailBrowseInfo(evaluationId)));
                return new ServiceReturn<>(ServiceStateCode.NO_SUCH_RECORD,null);
            }else{
                EvaluationDetailBrowseInfo finalInfo = info;
                CachedThreadPoolUtil.submit(()->esClient.saveDocument(finalInfo));
            }
        }
        return new ServiceReturn<>(ServiceStateCode.SUCCESS,info);
    }

    @Override
    public List<EvaluationBrowseInfo> obtainBrowseList(EvaluationQueryParam queryParam) {
        if(queryParam == null){
            queryParam = EvaluationQueryParam.builder()
                    .setSortOrder(SortOrder.DESC)
                    .build();
        }
        List<EvaluationBrowseInfo> searchResult = esClient.search(toElasticSearchQueryParam(queryParam), EvaluationBrowseInfo.class);
        if(searchResult.isEmpty() ||  searchResult.size()< queryParam.getPage().getPageSize()){
            searchResult = browseInfoDao.select(queryParam);
            //异步保存searchResult
            List<EvaluationBrowseInfo> finalSearchResult = searchResult;
            CachedThreadPoolUtil.submit(()->{
                if(finalSearchResult!=null){
                    esClient.bulkSave(finalSearchResult, WriteRequest.RefreshPolicy.NONE);
                }
            });
        }
        return searchResult;
    }

    @Override
    public List<EvaluationBrowseInfo> obtainBrowseListByGoodsClass(long goodsId, String userPurchasedGoodsClass,int pageIndex) {
        EvaluationQueryParam.Builder builder = EvaluationQueryParam.builder();
        builder.setGoodsId(goodsId)
                .setUserPurchasedGoodsClass(userPurchasedGoodsClass)
                .setPage(new Page(pageIndex,Page.DEFAULT_PAGE_SIZE));
        return obtainBrowseList(builder.build());
    }

    @Override
    public List<EvaluationBrowseInfo> obtainBrowseListByType(long goodsId, EvaluationType evaluationType,int pageIndex) {
        EvaluationQueryParam.Builder builder = EvaluationQueryParam.builder();
        builder.setGoodsId(goodsId)
                .setEvaluationType(evaluationType)
                .setPage(new Page(pageIndex,Page.DEFAULT_PAGE_SIZE));
        return obtainBrowseList(builder.build());
    }
}
